package com.bigknow.appstore.proxy.exceptions.processor.impl;

import com.bigknow.appstore.proxy.entity.ProxyLog;
import com.bigknow.appstore.proxy.enumerate.CallState;
import com.bigknow.appstore.proxy.enumerate.ErrorType;
import com.bigknow.appstore.proxy.exceptions.ProxyError;
import com.bigknow.appstore.proxy.exceptions.processor.IErrorProcessor;
import com.bigknow.appstore.proxy.log.ILogWriter;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;

import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;

import static com.bigknow.appstore.common.Assert.assertNotNull;

/**
 * 对异常信息进行统一处理类
 * Created by chaos on 2016/9/22.
 */
public class ErrorProcessor implements IErrorProcessor {

    private ILogWriter logWriter;

    public ErrorProcessor(ILogWriter logWriter) {
        assertNotNull(logWriter);
        this.logWriter = logWriter;
    }

    /**
     * 处理并记录错误信息
     *
     * @param ctx
     * @param error
     */
    @Override
    public void processError(ChannelHandlerContext ctx, ProxyError error) {
        processError(ctx.channel(), error);
    }

    /**
     * 通过channel来处理错误，并记录日志
     *
     * @param channel
     * @param error
     */
    @Override
    public void processError(Channel channel, ProxyError error) {
        assertNotNull(error);
        if (error.isSendResponseMessage()) {
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1
                    , getErrorStatus(error.getErrorType()));
            response.headers().set("proxyError", getErrorStatus(error.getErrorType()));
            response.headers().set("Content-type", "text/html; charset=utf-8");
            //此参数必须加上，因为发生错误后连接是必须关闭的
            response.headers().set("Connection", "close");
            String msg = createErrorHtmlMessage(error);
            try {
                response.headers().set("Content-Length", msg.getBytes("utf-8").length);
                response.content().writeBytes(msg.getBytes("utf-8"));
                channel.writeAndFlush(response);
                logWriter.writeLog(createProxyLog(error));
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        } else {
            logWriter.writeLog(createProxyLog(error));
            channel.close().awaitUninterruptibly();
        }
    }

    public ILogWriter getLogWriter() {
        return logWriter;
    }

    public void setLogWriter(ILogWriter logWriter) {
        this.logWriter = logWriter;
    }

    private ProxyLog createProxyLog(ProxyError error) {
        return logWriter.createErrorLogObject(error);
    }

    private String createErrorHtmlMessage(ProxyError error) {
        StringBuilder builder = new StringBuilder();
        builder.append("<!DOCTYPE html><html><head>")
                .append("<title>proxyServer - Error report</title>")
                .append("<style type=\"text/css\">")
                .append("H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;}")
                .append("H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;}")
                .append("H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;}")
                .append("BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;}")
                .append("B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;}")
                .append("P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}")
                .append("A {color : black;}A.name {color : black;}")
                .append(".line {height: 1px; background-color: #525D76; border: none;}")
                .append("</style>").append("</head>")
                .append("<body><h1>HTTP Status ").append(getErrorStatus(error.getErrorType())).append("- </h1>")
                .append("<div class=\"line\"></div>")
                .append("<p><b>type</b> ").append(error.getErrorType()).append("</p>")
                .append("<p><b>message</b> <u>").append(error.getErrorMessage()).append("</u></p>")
                .append("<hr class=\"line\"><h3>appStore </h3></body></html>");
        return builder.toString();


    }

    private HttpResponseStatus getErrorStatus(ErrorType errorType) {
        switch (errorType) {
            case SOURCE_ERROR:
            case SOURCE_CANNOT_CONN:
            case RESPONSE_ENCODING_ERROR:
                return HttpResponseStatus.INTERNAL_SERVER_ERROR;
            case PORXY_NO_LONGER_SERVE:
                return HttpResponseStatus.SERVICE_UNAVAILABLE;
            case URI_NO_PASS:
                return HttpResponseStatus.NOT_FOUND;
            default:
                return HttpResponseStatus.BAD_REQUEST;
        }
    }

}
